ext.define('extension.animation', function() {

function easeLinear(timediff, base, change, duration) {
    return change * timediff / duration + base;
}

function initialize(elem, time) {
    var value, attr, obj, answer = [], fromValue;
    elem.fx.start = time;
    elem.fx.from = [];
    for (attr in elem.fx.queue[0].attr) {
        value = elem.fx.queue[0].attr[attr];
        if (typeof value !== 'object') {
            obj = {};
            obj.value = value;
            obj.unit = 'px';
            value = obj;
        }
        else
            value.unit = value.unit !== undefined ? value.unit : 'px';
        fromValue = parseFloat(window.getComputedStyle(elem, null)[attr]);
        elem.fx.from[elem.fx.from.length] = isNaN(fromValue) ? 0 : fromValue;
        value.attr = attr;
        answer[answer.length] = value;
    }
    elem.fx.queue[0].attr = answer;
}

function step(elem) {
    var timediff = Date.now() - elem.fx.start,
        current = elem.fx.queue[0],
        duration = current.duration,
        style = ';',
        i = 0,
        row, value, from;
    duration < timediff && (timediff = duration);
    for (; i < elem.fx.queue[0].attr.length; i++) {
        row = elem.fx.queue[0].attr[i];
        from = elem.fx.from[i];
        value = current.easing(timediff, from, row.value - from, duration);
        style += row.attr + ':' + value + row.unit + ';';
    }
    elem.style.cssText += style;
    if (duration === timediff) {
        if (typeof elem.fx.queue[0].callback === 'function')
            elem.fx.queue[0].callback.call(elem);
        elem.fx.queue.shift();
        if (elem.fx.queue.length === 0) {
            elem.fx = false;
            return;
        }
        else
            initialize(elem, elem.fx.start + timediff);
    }
    elem.fx.timer = window.setTimeout(step, 30, elem);
};

function stop(element) {
    var elem = element;
    if (elem.fx && elem.fx.timer) {
        window.clearTimeout(elem.fx.timer);
        elem.fx = false;
    }
    return elem;
}

function start(element, attributes, options) {
    var elem = element, newRow = {};
    var opts = options || {};
    newRow.attr = attributes;
    newRow.callback = opts.callback;
    newRow.duration = opts.duration || 1000;
    newRow.easing = opts.easing || easeLinear;
    if (elem.fx)
        elem.fx.queue.push(newRow);
    else {
        elem.fx = {};
        elem.fx.queue = [newRow];
        initialize(elem, Date.now());
        elem.fx.timer = window.setTimeout(step, 30, elem);
    }
    return elem;
}

return {
    stop: stop,
    start: start
};

});
